"""
Celery任务定义
"""
import logging
from datetime import datetime
from typing import Dict, Any

from sqlalchemy.orm import Session

from app.core.database import SessionLocal
from app.models.deployment import Deployment, DeploymentHistory
from app.models.application import Application
from app.models.environment import Environment
from app.services.deploy_engine import deploy_engine
from app.services.celery_app import celery_app

logger = logging.getLogger(__name__)


@celery_app.task(bind=True)
def start_deployment_task(self, deployment_id: int) -> Dict[str, Any]:
    """启动部署任务"""
    db = SessionLocal()
    try:
        # 获取部署信息
        deployment = db.query(Deployment).filter(Deployment.id == deployment_id).first()
        if not deployment:
            return {"status": "failed", "message": "部署不存在"}
        
        application = db.query(Application).filter(Application.id == deployment.application_id).first()
        environment = db.query(Environment).filter(Environment.id == deployment.environment_id).first()
        
        if not application or not environment:
            return {"status": "failed", "message": "应用或环境不存在"}
        
        # 更新部署状态
        deployment.status = "running"
        deployment.started_at = datetime.utcnow()
        db.commit()
        
        # 执行部署
        result = deploy_engine.deploy(deployment, application, environment)
        
        # 更新部署结果
        if result["status"] == "success":
            deployment.status = "success"
            deployment.completed_at = datetime.utcnow()
            deployment.duration = int((deployment.completed_at - deployment.started_at).total_seconds())
        else:
            deployment.status = "failed"
            deployment.error_message = result.get("error", "部署失败")
            deployment.completed_at = datetime.utcnow()
            deployment.duration = int((deployment.completed_at - deployment.started_at).total_seconds())
        
        # 记录部署历史
        history = DeploymentHistory(
            deployment_id=deployment_id,
            action="deploy",
            status=deployment.status,
            message=result.get("message", ""),
            config_snapshot=deployment.config
        )
        db.add(history)
        db.commit()
        
        return result
        
    except Exception as e:
        logger.error(f"部署任务失败: {e}")
        
        # 更新部署状态为失败
        deployment = db.query(Deployment).filter(Deployment.id == deployment_id).first()
        if deployment:
            deployment.status = "failed"
            deployment.error_message = str(e)
            deployment.completed_at = datetime.utcnow()
            db.commit()
        
        return {"status": "failed", "error": str(e)}
    
    finally:
        db.close()


@celery_app.task(bind=True)
def stop_deployment_task(self, deployment_id: int) -> Dict[str, Any]:
    """停止部署任务"""
    db = SessionLocal()
    try:
        deployment = db.query(Deployment).filter(Deployment.id == deployment_id).first()
        if not deployment:
            return {"status": "failed", "message": "部署不存在"}
        
        # TODO: 实现停止部署逻辑
        deployment.status = "cancelled"
        deployment.completed_at = datetime.utcnow()
        db.commit()
        
        # 记录部署历史
        history = DeploymentHistory(
            deployment_id=deployment_id,
            action="stop",
            status="success",
            message="部署已停止"
        )
        db.add(history)
        db.commit()
        
        return {"status": "success", "message": "部署已停止"}
        
    except Exception as e:
        logger.error(f"停止部署任务失败: {e}")
        return {"status": "failed", "error": str(e)}
    
    finally:
        db.close()


@celery_app.task(bind=True)
def rollback_deployment_task(self, rollback_deployment_id: int, original_deployment_id: int) -> Dict[str, Any]:
    """回滚部署任务"""
    db = SessionLocal()
    try:
        rollback_deployment = db.query(Deployment).filter(Deployment.id == rollback_deployment_id).first()
        original_deployment = db.query(Deployment).filter(Deployment.id == original_deployment_id).first()
        
        if not rollback_deployment or not original_deployment:
            return {"status": "failed", "message": "部署不存在"}
        
        application = db.query(Application).filter(Application.id == rollback_deployment.application_id).first()
        environment = db.query(Environment).filter(Environment.id == rollback_deployment.environment_id).first()
        
        if not application or not environment:
            return {"status": "failed", "message": "应用或环境不存在"}
        
        # 更新回滚部署状态
        rollback_deployment.status = "running"
        rollback_deployment.started_at = datetime.utcnow()
        db.commit()
        
        # 执行回滚
        result = deploy_engine.rollback(rollback_deployment, rollback_deployment.version)
        
        # 更新回滚结果
        if result["status"] == "success":
            rollback_deployment.status = "success"
            rollback_deployment.completed_at = datetime.utcnow()
            rollback_deployment.duration = int((rollback_deployment.completed_at - rollback_deployment.started_at).total_seconds())
        else:
            rollback_deployment.status = "failed"
            rollback_deployment.error_message = result.get("error", "回滚失败")
            rollback_deployment.completed_at = datetime.utcnow()
            rollback_deployment.duration = int((rollback_deployment.completed_at - rollback_deployment.started_at).total_seconds())
        
        # 记录部署历史
        history = DeploymentHistory(
            deployment_id=rollback_deployment_id,
            action="rollback",
            status=rollback_deployment.status,
            message=result.get("message", ""),
            config_snapshot=rollback_deployment.config
        )
        db.add(history)
        db.commit()
        
        return result
        
    except Exception as e:
        logger.error(f"回滚任务失败: {e}")
        
        # 更新回滚部署状态为失败
        rollback_deployment = db.query(Deployment).filter(Deployment.id == rollback_deployment_id).first()
        if rollback_deployment:
            rollback_deployment.status = "failed"
            rollback_deployment.error_message = str(e)
            rollback_deployment.completed_at = datetime.utcnow()
            db.commit()
        
        return {"status": "failed", "error": str(e)}
    
    finally:
        db.close()


@celery_app.task(bind=True)
def health_check_task(self, deployment_id: int) -> Dict[str, Any]:
    """健康检查任务"""
    db = SessionLocal()
    try:
        deployment = db.query(Deployment).filter(Deployment.id == deployment_id).first()
        if not deployment:
            return {"status": "failed", "message": "部署不存在"}
        
        # 执行健康检查
        result = deploy_engine.health_check(deployment)
        
        # 记录健康检查结果
        history = DeploymentHistory(
            deployment_id=deployment_id,
            action="health_check",
            status=result["status"],
            message=result.get("message", "")
        )
        db.add(history)
        db.commit()
        
        return result
        
    except Exception as e:
        logger.error(f"健康检查任务失败: {e}")
        return {"status": "failed", "error": str(e)}
    
    finally:
        db.close()


@celery_app.task(bind=True)
def cleanup_old_deployments_task(self) -> Dict[str, Any]:
    """清理旧部署任务"""
    db = SessionLocal()
    try:
        # 清理30天前的部署记录
        from datetime import timedelta
        cutoff_date = datetime.utcnow() - timedelta(days=30)
        
        old_deployments = db.query(Deployment).filter(
            Deployment.created_at < cutoff_date,
            Deployment.status.in_(["success", "failed", "cancelled"])
        ).all()
        
        for deployment in old_deployments:
            # 删除部署历史
            db.query(DeploymentHistory).filter(
                DeploymentHistory.deployment_id == deployment.id
            ).delete()
            
            # 删除部署记录
            db.delete(deployment)
        
        db.commit()
        
        return {
            "status": "success",
            "message": f"清理了 {len(old_deployments)} 个旧部署记录"
        }
        
    except Exception as e:
        logger.error(f"清理任务失败: {e}")
        return {"status": "failed", "error": str(e)}
    
    finally:
        db.close()
